/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package edu.pdx.cs.guavadata;

import com.sun.org.apache.xpath.internal.axes.ChildIterator;
import edu.pdx.cs.guavadata.query.AddColumn;
import edu.pdx.cs.guavadata.query.AddElement;
import edu.pdx.cs.guavadata.query.AddTable;
import edu.pdx.cs.guavadata.query.AlterColumnRename;
import edu.pdx.cs.guavadata.query.AlterElementRename;
import edu.pdx.cs.guavadata.query.AlterTableRename;
import edu.pdx.cs.guavadata.query.AntiSemiJoin;
import edu.pdx.cs.guavadata.query.ApplyOp;
import edu.pdx.cs.guavadata.query.Check;
import edu.pdx.cs.guavadata.query.Command;
import edu.pdx.cs.guavadata.query.CrossJoin;
import edu.pdx.cs.guavadata.query.Delete;
import edu.pdx.cs.guavadata.query.DropColumn;
import edu.pdx.cs.guavadata.query.DropElement;
import edu.pdx.cs.guavadata.query.DropForeignKey;
import edu.pdx.cs.guavadata.query.DropTable;
import edu.pdx.cs.guavadata.query.Except;
import edu.pdx.cs.guavadata.query.Filter;
import edu.pdx.cs.guavadata.query.ForeignKey;
import edu.pdx.cs.guavadata.query.Insert;
import edu.pdx.cs.guavadata.query.Intersect;
import edu.pdx.cs.guavadata.query.Join;
import edu.pdx.cs.guavadata.query.Operator;
import edu.pdx.cs.guavadata.query.PivotOp;
import edu.pdx.cs.guavadata.query.Project;
import edu.pdx.cs.guavadata.query.RowConstant;
import edu.pdx.cs.guavadata.query.TableRef;
import edu.pdx.cs.guavadata.query.Union;
import edu.pdx.cs.guavadata.query.UnpivotOp;
import edu.pdx.cs.guavadata.query.Update;
import edu.pdx.cs.guavadata.subclass.Cell;
import edu.pdx.cs.guavadata.subclass.SemanticTransform;
import edu.pdx.cs.guavadata.subclass.SemanticUnit;
import java.sql.ResultSet;
import java.util.List;
import org.w3c.dom.Element;

/**
 *
 * @author VuTran
 */
public class Transform implements Cell {

    Cell child;

    public Cell getChild() {
        return child;
    }

    public void setChild(Cell child) {
        this.child = child;
    }

    public Transform inverse() {
        return this;
    }

    public void expand(AddColumn ac, Command c) {
        return;
    }

    public void expand(AddElement ae, Command c) {
        return;
    }

    public void expand(AddTable at, Command c) {
        return;
    }

    public void expand(AlterColumnRename acr, Command c) {
        return;
    }

    public void expand(AlterElementRename aer, Command c) {
        return;
    }

    public void expand(AlterTableRename atr, Command c) {
        return;
    }

    public void expand(AntiSemiJoin asj, Command c) {
        asj.getChild1().visit(this, c);
        asj.getChild2().visit(this, c);
    }

    public void expand(ApplyOp ao, Command c) {
        ao.getChild().visit(this, c);
    }

    public void expand(Check ch, Command c) {
        ch.getQuery1().visit(this, c);
        ch.getQuery2().visit(this, c);
    }

    public void expand(CrossJoin cj, Command c) {
        cj.getChild1().visit(this, c);
        cj.getChild2().visit(this, c);
    }

    public void expand(Delete d, Command c) {
        return;
    }

    public void expand(DropColumn dc, Command c) {
        return;
    }

    public void expand(DropElement de, Command c) {
        return;
    }

    public void expand(DropForeignKey dfk, Command c) {
        return;
    }

    public void expand(DropTable dt, Command c) {
        return;
    }

    public void expand(edu.pdx.cs.guavadata.query.Error er, Command c) {
        er.getQuery().visit(this, c);
    }

    public void expand(Except e, Command c) {
        e.getChild1().visit(this, c);
        e.getChild2().visit(this, c);
    }

    public void expand(Filter f, Command c) {
        f.getChild().visit(this, c);
    }

    public void expand(ForeignKey fk, Command c) {
        return;
    }

    public void expand(Insert i, Command c) {
        i.getChild().visit(this, c);
    }

    public void expand(Intersect i, Command c) {
        for (Operator o : i.getChildren()) {
            o.visit(this, c);
        }
    }

    public void expand(Join j, Command c) {
        j.getChild1().visit(this, c);
        j.getChild2().visit(this, c);
    }

    public void expand(Operator o, Command c) {
        try {
            throw new Exception("Unexpected operator discovered of type " + o.getClass().getName() + ".");
        } catch (Exception e) {
            System.err.println("ERROR: " + e.toString());
        }
    }

    public void expand(PivotOp po, Command c) {
        po.getChild().visit(this, c);
    }

    public void expand(Project p, Command c) {
        p.getChild().visit(this, c);
    }

    public void expand(RowConstant tc, Command c) {
        return;
    }

    public void expand(TableRef tr, Command c) {
        return;
    }

    public void expand(Union u, Command c) {
        for (Operator o : u.getChildren()) {
            o.visit(this, c);
        }
    }

    public void expand(UnpivotOp uo, Command c) {
        uo.getChild().visit(this, c);
    }

    public void expand(Update u, Command c) {
        u.getChild().visit(this, c);
    }

    public ResultSet process(Transaction o) {
        for (Command c : o.contents)
            c.root.visit(this, c);
        o.complete();
        return child.process(o);
    }

    public List<SemanticUnit> semanticUnits(String table) {
        if (this instanceof SemanticTransform) {
            List<SemanticUnit> lsu = child.semanticUnits(table);
            ((SemanticTransform) this).buildUnits(table, lsu);
            return lsu;
        } else {
            return child.semanticUnits(table);
        }
    }

    public static Transform fromElement(Element e) {
        try {
            if (!e.getNodeName().equals("Transform"))
                throw new Exception("XElement is not of type Transform");
        
            // What type should the new transfrom be?
            String type = e.getAttribute("type");

            if (type.equals("VMerge"))
                return VMerge.fromElement(e);
            if (type.equals("VSplit"))
                return VSplit.fromElement(e);
            if (type.equals("HMerge"))
                return HMerge.fromElement(e);
            if (type.equals("HSplit"))
                return HSplit.fromElement(e);
            if (type.equals("Unpivot"))
                return Unpivot.fromElement(e);
            if (type.equals("Apply"))
                return Apply.fromElement(e);
            //if (type.equals("Adorn")
                //return Adorn.FromXElement(xe);
            //if (type == "Pivot")
                //return Pivot.FromXElement(xe);

      
            throw new Exception("Transformation type is unknown");
        } catch (Exception ex) {
            System.err.println("ERROR: " + e.toString());
        }
        return null;
    }

}
